import { Guid } from "../Utils/Guid";
import { IncomingMessage } from "./InComingMessage";
import { OutgoingMessage } from "./OutgoingMessage";
import { SideChannel } from "./SideChannel";

/**
 * @en
 * Side channel that is comprised of a collection of float variables.
 * @zh
 * 由一组浮点变量组成的侧通道。
 */
export class FloatPropertiesChannel extends SideChannel {
    private _floatProperties: Map<string, number> = new Map();

    private _registeredActions: Map<string, (value: number) => void> = new Map();

    private static readonly _floatPropertiesDefaultId: string = "60ccf7d0-4f7e-11ea-b238-784f4387d1f7";

    private _channelId: Guid;

    constructor(channelId: Guid = Guid.empty()) {
        super();
        if (channelId.uuid === Guid.empty().uuid) {
            this._channelId = new Guid(FloatPropertiesChannel._floatPropertiesDefaultId);
        } else {
            this._channelId = channelId;
        }
    }

    onMessageReceived(msg: IncomingMessage): void {
        const key: string = msg.readString();
        const value: number = msg.readFloat32();
        this._floatProperties.set(key, value);
        const action = this._registeredActions.get(key);
        if (action) {
            action(value);
        }
    }

    /**
     * @en
     * Sets one of the float properties of the environment. This data will be sent to Python.
     * 
     * @zh 
     * 设置环境的浮点属性之一。此数据将发送到 Python。
     * @param key 
     * @param value 
     */
    public set(key: string, value: number): void {
        this._floatProperties.set(key, value);
        const msgOut = new OutgoingMessage();
        msgOut.writeString(key);
        msgOut.writeFloat32(value);
        this.queueMessageToSend(msgOut);

        const action = this._registeredActions.get(key);
        if (action) {
            action(value);
        }
    }

    public getWithDefault(key: string, defaultValue: number): number {
        const valueOut = this._floatProperties.get(key);
        return valueOut !== undefined ? valueOut : defaultValue;
    }

    /**
     * @en
     * Registers an action to be performed everytime the property is changed.
     * @zh
     * 注册一个回调，每次更改属性时都会执行。
     * @param key 
     * @param action 
     */
    public registerCallback(key: string, action: (value: number) => void): void {
        this._registeredActions.set(key, action);
    }

    public keys(): string[] {
        return Array.from(this._floatProperties.keys());
    }

}